package com.example.spring_gobang.api;

import com.example.spring_gobang.common.AppVariable;
import com.example.spring_gobang.game.OnlineUserManage;
import com.example.spring_gobang.game.Room;
import com.example.spring_gobang.game.RoomManager;
import com.example.spring_gobang.messgae.GameReadyResponse;
import com.example.spring_gobang.messgae.GameResponse;
import com.example.spring_gobang.model.UserInfo;
import com.example.spring_gobang.service.UserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Component
public class Game extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private RoomManager roomManager;
    @Autowired
    private OnlineUserManage onlineUserManage;
    @Resource
    private UserService userService;
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        GameReadyResponse resp = new GameReadyResponse();
        //TODO 判断用户是否已经登录
        UserInfo userInfo = (UserInfo) session.getAttributes().get(AppVariable.USER_SESSION_KEY);
        if (userInfo == null) {
            resp.setOk(false);
            resp.setReason("用户尚未登录!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        //TODO 判断用户是否已经进入到游戏房间
        Room room = roomManager.getRoomeByUserId(userInfo.getUserId());
        if (room == null) {
            // 如果为 null, 当前没有找到对应的房间. 该玩家还没有匹配到.
            resp.setOk(false);
            resp.setReason("用户尚未匹配到!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        //TODO 防止用户多开
        if (onlineUserManage.getFromById(userInfo.getUserId()) != null
                || onlineUserManage.getRoomById(userInfo.getUserId()) != null) {
            // 如果一个账号, 一边是在游戏大厅, 一边是在游戏房间, 也视为多开~~
            resp.setOk(true);
            resp.setReason("禁止多开游戏页面");
            resp.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        //设置玩家在游戏房间进入上线状态
        onlineUserManage.enterGameRoom(userInfo.getUserId(), session);
        //TODO 把两个玩家加入到游戏房间
        //如果两个客户端同时执行到这个逻辑 就可能会出现线程安全问题
        //两个客户端都认为自己应该是先手方
        System.out.println(userInfo.getUsername());
        synchronized (room) {
            //针对房间对象加锁 只有想要进入一个房间客户端才是互斥使用的
            if (room.getUserInfo1() == null){
                //如果玩家1还未设置 就把当前连接websocket的用户设置为玩家1
                room.setUserInfo1(userInfo);
                //规定 谁是玩家1 谁先手
                room.setWhiteUser(userInfo.getUserId());
                System.out.println("玩家1" + userInfo.getUsername() + "已就绪！");
                return;
            }
            //此时玩家1已经加入游戏放假
            //则把当前连接的用户设置为玩家2
            if (room.getUserInfo2() == null){
                room.setUserInfo2(userInfo);
                System.out.println("玩家2" + userInfo.getUsername() + "已就绪！");
                //当两个玩家都已进入到同一个游戏房间的时候
                //由服务器去通知两个客户端 你俩匹配到对手了
                //通知玩家1
                noticeGameReady(room,room.getUserInfo1(),room.getUserInfo2());
                //通知玩家2
                noticeGameReady(room,room.getUserInfo2(),room.getUserInfo1());
                return;
            }
        }
    }

    private void noticeGameReady(Room room, UserInfo thisUser, UserInfo thatUser) throws IOException {
        GameReadyResponse response = new GameReadyResponse();
        response.setOk(true);
        response.setReason("");
        response.setMessage("gameReady");
        response.setRoomId(room.getRoomId());
        response.setThisUserId(thisUser.getUserId());
        response.setThatUserId(thatUser.getUserId());
        response.setWhiteUser(room.getWhiteUser());
        //把构造好的相应传给对应的客户端
        WebSocketSession session = onlineUserManage.getRoomById(thisUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get(AppVariable.USER_SESSION_KEY);
        if (userInfo == null){
            return;
        }
        // 2. 根据玩家 id 获取到房间对象
        Room room = roomManager.getRoomeByUserId(userInfo.getUserId());
        // 3. 通过 room 对象来处理这次落子的请求
        room.putChess(message.getPayload());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get(AppVariable.USER_SESSION_KEY);
        if (userInfo == null){
            return;
        }
        WebSocketSession tmpSession = onlineUserManage.getRoomById(userInfo.getUserId());
        if (tmpSession == session){
            //防止多开操作 第二个用户断开连接 导致第一个用户的连接也断开了
            onlineUserManage.exitGameRoom(userInfo.getUserId());
        }
        System.out.println("玩家" + userInfo.getUsername() + "游戏连接异常！");
        //出现错误 直接通知对手胜利
        noticeThatUserWin(userInfo);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        UserInfo userInfo = (UserInfo) session.getAttributes().get(AppVariable.USER_SESSION_KEY);
        if (userInfo == null){
            return;
        }
        WebSocketSession tmpSession = onlineUserManage.getRoomById(userInfo.getUserId());
        if (tmpSession == session){
            //防止多开操作 第二个用户断开连接 导致第一个用户的连接也断开了
            onlineUserManage.exitGameRoom(userInfo.getUserId());
        }
        System.out.println("玩家" + userInfo.getUsername() + "离开游戏房间！");
        //游戏房间页面关闭 直接通知对手胜利
        noticeThatUserWin(userInfo);
    }

    private void noticeThatUserWin(UserInfo userInfo) throws IOException {
        //根据当前出现问题的用户找到当前放房间
        Room room = roomManager.getRoomeByUserId(userInfo.getUserId());
        if (room == null){
            //如果当前房间不存在 那还通知个毛线
            return;
        }
        //根据房间找到对手
        UserInfo tharUser =(room.getUserInfo1() == userInfo) ? room.getUserInfo2() : room.getUserInfo1();
        WebSocketSession session = onlineUserManage.getRoomById(tharUser.getUserId());
        if (session == null){
            //如果对手也是掉线了 那么这局就黄了
            System.out.println("这把黄了");
            return;
        }
        //构造一个响应通知对手 这局算你赢
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setUserId(tharUser.getUserId());
        response.setWinner(tharUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        //胜负已分
        int winnerId = response.getWinner();
        int loseId = userInfo.getUserId();
        userService.userWin(winnerId);
        userService.userLose(loseId);
        //这局游戏已经结束 释放这个房间
        roomManager.remove(room.getRoomId(),userInfo.getUserId(),tharUser.getUserId());
    }
}
